package com

import (
	"alex/ptp1588boundaryclock/datasets"
)

type Header struct {
	DefaultDS *datasets.DefaultDS
	PortDS *datasets.PortDS
	TimePropertiesDS *datasets.TimePropertiesDS
	MsgType MessageType
	MessageLength uint16
	SequenceID uint16
}

const (
	HeaderLength uint8 = 34
)

// Init needed coz of Pointers
func (h* Header) Init() {
	h.DefaultDS = new(datasets.DefaultDS)
	h.PortDS = new(datasets.PortDS)
	h.TimePropertiesDS = new(datasets.TimePropertiesDS)
}

// =====================================================================================================================
// Write Header
// =====================================================================================================================

// Creates the header as specified in 13.3
func (h *Header) Write(header []byte, done chan bool) {
	// transportSpecific AND messageType
	header[0] = byte(h.MsgType)
	// reserved AND versionPTP (2)
	header[1] = h.PortDS.VersionNumber
	// messageLength
	header[2], header[3] = h.calculateMessageLength()
	// domainNumber -> defaultDS.domainNumber
	header[4] = h.DefaultDS.DomainNumber
	// reserved -> 0
	header[5] = 0
	// flagField
	header[6], header[7] = h.setHeaderFlagField()
	// correction field int64 -> seems unimportant and reserved (16, 17, 18, 19)
	for i := 8; i < 20; i++ {
		header[i] = 0
	}
	// sourcePortIdentity PortIdentity
	h.setHeaderPortIdentity(header[20:30])
	// sequenceID of the message
	header[30], header[31] = uint8(h.SequenceID>>8), uint8(h.SequenceID)
	// controlField -> DEPRECATED
	header[32] = h.setHeaderControlField()
	// logMessageInterval
	header[33] = h.setHeaderLogMessageInterval()
	done <- true
}

// Calculates the length of the message
// Will be larger than the header (34)
func (h *Header) calculateMessageLength() (byte, byte) {
	length := uint16(h.MsgType.GetLength() + HeaderLength)
	return uint8(length >> 8), uint8(length)
}

// Sets the header flag filed as specified in 13.3.2.6
func (h *Header) setHeaderFlagField() (flagField1 byte, flagField2 byte) {
	// TO: i versteh 13.3 Table 20 net
	// Byte 1
	if h.MsgType == Announce || h.MsgType == Sync || h.MsgType == Follow_Up || h.MsgType == Delay_Resp {
		flagField1 += 0
	}

	if (h.MsgType == Sync || h.MsgType == Pdelay_Resp) && h.DefaultDS.TwoStepFlag {
		flagField1 += (1<<1)
	}

	// TODO: if unicast und rest
	// Byte 2
	if h.MsgType == Announce {
		if h.TimePropertiesDS.Leap61 {
			flagField2 += 1
		}
		if h.TimePropertiesDS.Leap59 {
			flagField2 += (1<<1)
		}
		if h.TimePropertiesDS.CurrentUtcOffsetValid {
			flagField2 += (1<<2)
		}
		if h.TimePropertiesDS.PtpTimescale {
			flagField2 += (1<<3)
		}
		if h.TimePropertiesDS.TimeTraceable {
			flagField2 += (1<<4)
		}
		if h.TimePropertiesDS.FrequencyTraceable {
			flagField2 += (1<<5)
		}
	}
	return
}

// Sets the PortIdentity field
// 13.3.2.8
func (h* Header) setHeaderPortIdentity(identity []byte) {
	for key, value := range h.PortDS.PortIdentity.ClockIdentity {
		identity[key] = value
	}
	identity[8], identity[9] = uint8(h.PortDS.PortIdentity.PortNumber >> 8), uint8(h.PortDS.PortIdentity.PortNumber)
}

// Sets the deprecated ControlField
// 13.3.2.10
func (h* Header) setHeaderControlField() (ctrlField byte) {
	if h.MsgType == Sync {
		ctrlField = 0x00
	} else if h.MsgType == Delay_Req {
		ctrlField = 0x01
	} else if h.MsgType == Follow_Up {
		ctrlField = 0x02
	} else if h.MsgType == Delay_Resp {
		ctrlField = 0x03
	} else if h.MsgType == Management {
		ctrlField = 0x04
	} else {
		ctrlField = 0x05
	}
	return
}

// Sets logMessageInterval 13.3.2.11
func (h* Header) setHeaderLogMessageInterval() (log byte) {
	if h.MsgType == Announce {
		log = uint8(h.PortDS.LogAnnouncedInterval)
	} else if h.MsgType == Sync || h.MsgType == Follow_Up {
		// TODO: Multicast
		log = 0x7f
	} else if h.MsgType == Delay_Resp {
		// TODO: Multicast
		log = 0x7f
	} else {
		log = 0x7f
	}
	return
}

// =====================================================================================================================
// Read Header
// =====================================================================================================================

// bool is initialized with FALSE
// Reads a byte slice and checks if it is a valid header
func (h* Header) Read(header []byte, read uint16) (check bool) {
	// transportSpecific and MessageType 13.3.2.2
	h.MsgType = MessageType(header[0])
	// check if messageType is valid via GetLength() method
	if h.MsgType.GetLength() == 10 || h.MsgType.GetLength() == 20 || h.MsgType.GetLength() == 30 {
		// set versionPTP and check if valid 13.3.2.3
		if h.PortDS.VersionNumber = header[1]; h.PortDS.VersionNumber == 2 {
			// set and check messageLength 13.3.2.4
			h.MessageLength = uint16(header[2]) << 8 | uint16(header[3])
			if h.MessageLength == read {
				// sets domainNumber 13.3.2.5
				if h.DefaultDS.DomainNumber = header[4]; header[5] == 0 {
					// sets and checks flagField 13.3.2.6
					if h.readHeaderFlagField(header[6:8]) {
						// checks correctionField 13.3.2.7
						tmpCheck := true
						for i := 8; i < 20; i++ {
							if header[i] != 0 {
								tmpCheck = false
							}
						}
						if tmpCheck {
							// Set portIdentity
							h.readHeaderPortIdentity(header[20:30])
							// TODO: sequenceID -> header[30], header[31]
							// check controlField
							if h.readControlField(header[32]) && h.readLogMessageInterval(header[33]){
								check = true
							}
						}
					}
				}
			}
		}
	}
	return
}

// Reads the Header Flag Field and sets the associated values as defined in 13.3.2.6
func (h* Header) readHeaderFlagField(flag[] byte) (check bool) {
	check = true
	// Byte 1
	if flag[0] & (1<<7) != 0 {
		check = false
	}

	if !(h.MsgType == Sync || h.MsgType == Pdelay_Resp) && (flag[1] & (1<<1) != 0) {
		check = false
	}
	if h.MsgType == Sync || h.MsgType == Pdelay_Resp {
		if flag[1] & (1<<1) == (1<<1) {
			h.DefaultDS.TwoStepFlag = true
		}
	}

	// Byte 2
	if h.MsgType != Announce && flag[1] > 0 {
		check = false
	} else if h.MsgType == Announce {
		if flag[1] & 1 == 1 {
			h.TimePropertiesDS.Leap61 = true
		}
		if flag[1] & (1<<1) == (1<<1) {
			h.TimePropertiesDS.Leap59 = true
		}
		if flag[1] & (1<<2) == (1<<2) {
			h.TimePropertiesDS.CurrentUtcOffsetValid = true
		}
		if flag[1] & (1<<3) == (1<<3) {
			h.TimePropertiesDS.PtpTimescale = true
		}
		if flag[1] & (1<<4) == (1<<4) {
			h.TimePropertiesDS.TimeTraceable = true
		}
		if flag[1] & (1<<5) == (1<<5) {
			h.TimePropertiesDS.FrequencyTraceable = true
		}
		if flag[1] & 0xc0 != 0 {
			check = false
		}
	}
	return
}

// Reads and sets sourcePortIdentity 13.3.2.8
// TODO: Return bool and check PortIdentity and PortNumber
func (h* Header) readHeaderPortIdentity(identity[] byte) {
	// for range loop does not work since identity is longer than ClockIdentity - sad-me-face
	for i := 0; i < len(h.PortDS.PortIdentity.ClockIdentity); i++ {
		h.PortDS.PortIdentity.ClockIdentity[i] = identity[i]
	}
	h.PortDS.PortIdentity.PortNumber = uint16(identity[8]) << 8 | uint16(identity[9])
}

// Reads and checks the controlField 13.3.2.10
func (h* Header) readControlField(ctrlField byte) (check bool) {
	if ctrlField == 0x00 && h.MsgType == Sync {
		check = true
	} else if ctrlField == 0x01 && h.MsgType == Delay_Req {
		check = true
	} else if ctrlField == 0x02 && h.MsgType == Follow_Up {
		check = true
	} else if ctrlField == 0x03 && h.MsgType == Delay_Resp {
		check = true
	} else if ctrlField == 0x05 && h.MsgType == Management {
		check = true
	} else if ctrlField == 0x05 && (h.MsgType == Pdelay_Resp || h.MsgType == Pdelay_Req ||
		h.MsgType == Pdelay_Resp_Follow_Up || h.MsgType == Announce || h.MsgType == Signaling) {
		check = true
	}
	return
}

// Reads and checks logMessageInterval 13.3.2.11
// TODO: Multicast
func (h* Header) readLogMessageInterval(log byte) (check bool) {
	if h.MsgType == Announce {
		h.PortDS.LogAnnouncedInterval = int8(log)
		check = true
	} else if (h.MsgType == Sync || h.MsgType == Follow_Up) && log == 0x7f {
		check = true
	} else if h.MsgType == Delay_Resp && log == 0x7f {
		check = true
	} else if log == 0x7f {
		check = true
	}
	return
}
